home *** CD-ROM | disk | FTP | other *** search
/ Internet Info 1994 March / Internet Info CD-ROM (Walnut Creek) (March 1994).iso / networking / ip / ka9q / src890906.arc / FTPSERV.C < prev    next >
C/C++ Source or Header  |  1989-09-07  |  16KB  |  683 lines

  1. /* FTP Server state machine - see RFC 959 */
  2. #include <stdio.h>
  3. #include <ctype.h>
  4. #include <time.h>
  5. #ifdef    __TURBOC__
  6. #include <io.h>
  7. #include <dir.h>
  8. #endif
  9. #include "global.h"
  10. #include "mbuf.h"
  11. #include "socket.h"
  12. #include "ftp.h"
  13. #include "ftpserv.h"
  14. #include "proc.h"
  15. #include "dirutil.h"
  16.  
  17. static void ftpserv __ARGS((int s,void *unused,void *p));
  18. static int pport __ARGS((struct sockaddr_in *sock,char *arg));
  19. static void ftplogin __ARGS((struct ftpserv *ftp,char *pass));
  20. static int sendit __ARGS((struct ftpserv *ftp,char *command,char *file));
  21. static int recvit __ARGS((struct ftpserv *ftp,char *command,char *file));
  22. static int permcheck __ARGS((struct ftpserv *ftp,int op,char *file));
  23.  
  24. extern char Hostname[],Version[];
  25.  
  26. /* Command table */
  27. static char *commands[] = {
  28.     "user",
  29. #define    USER_CMD    0
  30.     "acct",
  31. #define    ACCT_CMD    1
  32.     "pass",
  33. #define    PASS_CMD    2
  34.     "type",
  35. #define    TYPE_CMD    3
  36.     "list",
  37. #define    LIST_CMD    4
  38.     "cwd",
  39. #define    CWD_CMD        5
  40.     "dele",
  41. #define    DELE_CMD    6
  42.     "name",
  43. #define    NAME_CMD    7
  44.     "quit",
  45. #define    QUIT_CMD    8
  46.     "retr",
  47. #define    RETR_CMD    9
  48.     "stor",
  49. #define    STOR_CMD    10
  50.     "port",
  51. #define    PORT_CMD    11
  52.     "nlst",
  53. #define    NLST_CMD    12
  54.     "pwd",
  55. #define    PWD_CMD        13
  56.     "xpwd",            /* For compatibility with 4.2BSD */
  57. #define    XPWD_CMD    14
  58.     "mkd ",
  59. #define    MKD_CMD        15
  60.     "xmkd",            /* For compatibility with 4.2BSD */
  61. #define    XMKD_CMD    16
  62.     "xrmd",            /* For compatibility with 4.2BSD */
  63. #define    XRMD_CMD    17
  64.     "rmd ",
  65. #define    RMD_CMD        18
  66.     "stru",
  67. #define    STRU_CMD    19
  68.     "mode",
  69. #define    MODE_CMD    20
  70.     NULLCHAR
  71. };
  72.  
  73. /* Response messages */
  74. static char banner[] = "220 %s FTP version %s ready at %s\r\n";
  75. static char badcmd[] = "500 Unknown command\r\n";
  76. static char unsupp[] = "500 Unsupported command or option\r\n";
  77. static char givepass[] = "331 Enter PASS command\r\n";
  78. static char logged[] = "230 Logged in\r\n";
  79. static char typeok[] = "200 Type %s OK\r\n";
  80. static char only8[] = "501 Only logical bytesize 8 supported\r\n";
  81. static char deleok[] = "250 File deleted\r\n";
  82. static char mkdok[] = "200 MKD ok\r\n";
  83. static char delefail[] = "550 Delete failed: %s\r\n";
  84. static char pwdmsg[] = "257 \"%s\" is current directory\r\n";
  85. static char badtype[] = "501 Unknown type \"%s\"\r\n";
  86. static char badport[] = "501 Bad port syntax\r\n";
  87. static char unimp[] = "502 Command not yet implemented\r\n";
  88. static char bye[] = "221 Goodbye!\r\n";
  89. static char nodir[] = "553 Can't read directory \"%s\": %s\r\n";
  90. static char cantopen[] = "550 Can't read file \"%s\": %s\r\n";
  91. static char sending[] = "150 Opening data connection for %s %s\r\n";
  92. static char cantmake[] = "553 Can't create \"%s\": %s\r\n";
  93. static char writerr[] = "552 Write error: %s\r\n";
  94. static char portok[] = "200 Port command okay\r\n";
  95. static char rxok[] = "226 File received OK\r\n";
  96. static char txok[] = "226 File sent OK\r\n";
  97. static char noperm[] = "550 Permission denied\r\n";
  98. static char noconn[] = "425 Data connection reset\r\n";
  99. static char notlog[] = "530 Please log in with USER and PASS\r\n";
  100. static char okay[] = "200 Ok\r\n";
  101.  
  102. static int Sftp = -1;    /* Prototype socket for service */
  103.  
  104. /* Start up FTP service */
  105. int
  106. ftpstart(argc,argv,p)
  107. int argc;
  108. char *argv[];
  109. void *p;
  110. {
  111.     struct sockaddr_in lsocket;
  112.     int s;
  113.  
  114.     if(Sftp != -1){
  115.         /* Already running! */
  116.         freeargs(argc,argv);
  117.         return 0;
  118.     }
  119.     psignal(Curproc,0);    /* Don't keep the parser waiting */
  120.     chname(Curproc,"FTP listener");
  121.  
  122.     lsocket.sin_family = AF_INET;
  123.     lsocket.sin_addr.s_addr = Ip_addr;
  124.     if(argc < 2)
  125.         lsocket.sin_port = IPPORT_FTP;
  126.     else
  127.         lsocket.sin_port = atoi(argv[1]);
  128.  
  129.     freeargs(argc,argv);
  130.     Sftp = socket(AF_INET,SOCK_STREAM,0);
  131.     bind(Sftp,(char *)&lsocket,sizeof(lsocket));
  132.     listen(Sftp,1);
  133.     for(;;){
  134.         if((s = accept(Sftp,NULLCHAR,(int *)NULL)) == -1)
  135.             break;    /* Service is shutting down */
  136.  
  137.         /* Spawn a server */
  138.         newproc("ftpserv",2048,ftpserv,s,NULL,NULL);
  139.     }
  140.     return 0;
  141. }
  142. static void
  143. ftpserv(s,unused,p)
  144. int s;    /* Socket with user connection */
  145. void *unused;
  146. void *p;
  147. {
  148.     struct ftpserv ftp;
  149.     char **cmdp,buf[512],*arg,*cp,*cp1,*file,*mode;
  150.     long t;
  151.     int cnt,i;
  152.     struct sockaddr_in socket;
  153.  
  154.     memset((char *)&ftp,0,sizeof(ftp));    /* Start with clear slate */
  155.     ftp.data = -1;
  156.  
  157.     sockowner(s,Curproc);        /* We own it now */
  158.     ftp.control = s;
  159.     /* Set default data port */
  160.     i = SOCKSIZE;
  161.     getpeername(s,(char *)&socket,&i);
  162.     socket.sin_port = IPPORT_FTPD;
  163.     ASSIGN(ftp.port,socket);
  164.  
  165.     log(s,"open FTP");
  166.     time(&t);
  167.     cp = ctime(&t);
  168.     if((cp1 = strchr(cp,'\n')) != NULLCHAR)
  169.         *cp1 = '\0';
  170.     usprintf(s,banner,Hostname,Version,cp);
  171. loop:    if((cnt = recvline(s,buf,sizeof(buf))) == -1){
  172.         /* He closed on us */
  173.         goto finish;
  174.     }
  175.     if(cnt == 0){
  176.         /* Can't be a legal FTP command */
  177.         usprintf(ftp.control,badcmd);
  178.         goto loop;
  179.     }    
  180.     rip(buf);
  181. #ifdef    UNIX
  182.     /* Translate first word to lower case */
  183.     for(cp = buf;*cp != ' ' && *cp != '\0';cp++)
  184.         *cp = tolower(*cp);
  185. #else
  186.     /* Translate entire buffer to lower case */
  187.     for(cp = buf;*cp != '\0';cp++)
  188.         *cp = tolower(*cp);
  189. #endif
  190.     /* Find command in table; if not present, return syntax error */
  191.     for(cmdp = commands;*cmdp != NULLCHAR;cmdp++)
  192.         if(strncmp(*cmdp,buf,strlen(*cmdp)) == 0)
  193.             break;
  194.     if(*cmdp == NULLCHAR){
  195.         usprintf(ftp.control,badcmd);
  196.         goto loop;
  197.     }
  198.     /* Allow only USER, PASS and QUIT before logging in */
  199.     if(ftp.cd == NULLCHAR || ftp.path == NULLCHAR){
  200.         switch(cmdp-commands){
  201.         case USER_CMD:
  202.         case PASS_CMD:
  203.         case QUIT_CMD:
  204.             break;
  205.         default:
  206.             usprintf(ftp.control,notlog);
  207.             goto loop;
  208.         }
  209.     }
  210.     arg = &buf[strlen(*cmdp)];
  211.     while(*arg == ' ')
  212.         arg++;
  213.  
  214.     /* Execute specific command */
  215.     switch(cmdp-commands){
  216.     case USER_CMD:
  217.         free(ftp.username);
  218.         if((ftp.username = strdup(arg)) == NULLCHAR){
  219.             shutdown(ftp.control,1);
  220.             goto finish;
  221.         }
  222.         usprintf(ftp.control,givepass);
  223.         break;
  224.     case TYPE_CMD:
  225.         switch(arg[0]){
  226.         case 'A':
  227.         case 'a':    /* Ascii */
  228.             ftp.type = ASCII_TYPE;
  229.             usprintf(ftp.control,typeok,arg);
  230.             break;
  231.         case 'l':
  232.         case 'L':
  233.             while(*arg != ' ' && *arg != '\0')
  234.                 arg++;
  235.             if(*arg == '\0' || *++arg != '8'){
  236.                 usprintf(ftp.control,only8);
  237.                 break;
  238.             }
  239.             ftp.type = LOGICAL_TYPE;
  240.             ftp.logbsize = 8;
  241.             usprintf(ftp.control,typeok,arg);
  242.             break;
  243.         case 'B':
  244.         case 'b':    /* Binary */
  245.         case 'I':
  246.         case 'i':    /* Image */
  247.             ftp.type = IMAGE_TYPE;
  248.             usprintf(ftp.control,typeok,arg);
  249.             break;
  250.         default:    /* Invalid */
  251.             usprintf(ftp.control,badtype,arg);
  252.             break;
  253.         }
  254.         break;
  255.     case QUIT_CMD:
  256.         usprintf(ftp.control,bye);
  257.         goto finish;
  258.     case RETR_CMD:
  259.         file = pathname(ftp.cd,arg);
  260.         switch(ftp.type){
  261.         case IMAGE_TYPE:
  262.         case LOGICAL_TYPE:
  263.             mode = READ_BINARY;
  264.             break;
  265.         case ASCII_TYPE:
  266.             mode = READ_TEXT;
  267.             break;
  268.         }
  269.         if(!permcheck(&ftp,RETR_CMD,file)){
  270.              usprintf(ftp.control,noperm);
  271.         } else if((ftp.fp = fopen(file,mode)) == NULLFILE){
  272.             usprintf(ftp.control,cantopen,file,sys_errlist[errno]);
  273.         } else {
  274.             log(ftp.control,"RETR %s",file);
  275.             sendit(&ftp,"RETR",file);
  276.         }
  277.         free(file);
  278.         break;
  279.     case STOR_CMD:
  280.         file = pathname(ftp.cd,arg);
  281.         switch(ftp.type){
  282.         case IMAGE_TYPE:
  283.         case LOGICAL_TYPE:
  284.             mode = WRITE_BINARY;
  285.             break;
  286.         case ASCII_TYPE:
  287.             mode = WRITE_TEXT;
  288.             break;
  289.         }
  290.         if(!permcheck(&ftp,STOR_CMD,file)){
  291.              usprintf(ftp.control,noperm);
  292.         } else if((ftp.fp = fopen(file,mode)) == NULLFILE){
  293.             usprintf(ftp.control,cantmake,file,sys_errlist[errno]);
  294.         } else {
  295.             log(ftp.control,"STOR %s",file);
  296.             recvit(&ftp,"STOR",file);
  297.         }
  298.         free(file);
  299.         break;
  300.     case PORT_CMD:
  301.         if(pport(&ftp.port,arg) == -1){
  302.             usprintf(ftp.control,badport);
  303.         } else {
  304.             usprintf(ftp.control,portok);
  305.         }
  306.         break;
  307. #ifndef CPM
  308.     case LIST_CMD:
  309.         file = pathname(ftp.cd,arg);
  310.         if(!permcheck(&ftp,RETR_CMD,file)){
  311.              usprintf(ftp.control,noperm);
  312.         } else if((ftp.fp = dir(file,1)) == NULLFILE){
  313.             usprintf(ftp.control,nodir,file,sys_errlist[errno]);
  314.         } else {
  315.             sendit(&ftp,"LIST",file);
  316.         }
  317.         free(file);
  318.         break;
  319.     case NLST_CMD:
  320.         file = pathname(ftp.cd,arg);
  321.         if(!permcheck(&ftp,RETR_CMD,file)){
  322.              usprintf(ftp.control,noperm);
  323.         } else if((ftp.fp = dir(file,0)) == NULLFILE){
  324.             usprintf(ftp.control,nodir,file,sys_errlist[errno]);
  325.         } else {
  326.             sendit(&ftp,"NLST",file);
  327.         }
  328.         free(file);
  329.         break;
  330.     case CWD_CMD:
  331.         file = pathname(ftp.cd,arg);
  332.         if(!permcheck(&ftp,RETR_CMD,file)){
  333.              usprintf(ftp.control,noperm);
  334.             free(file);
  335. #ifdef    MSDOS
  336.         /* Don'tcha just LOVE %%$#@!! MS-DOS? */
  337.         } else if(strcmp(file,"/") == 0 || access(file,0) == 0){
  338. #else
  339.         } else if(access(file,0) == 0){    /* See if it exists */
  340. #endif
  341.             /* Succeeded, record in control block */
  342.             free(ftp.cd);
  343.             ftp.cd = file;
  344.             usprintf(ftp.control,pwdmsg,file);
  345.         } else {
  346.             /* Failed, don't change anything */
  347.             usprintf(ftp.control,nodir,file,sys_errlist[errno]);
  348.             free(file);
  349.         }
  350.         break;
  351.     case XPWD_CMD:
  352.     case PWD_CMD:
  353.         usprintf(ftp.control,pwdmsg,ftp.cd);
  354.         break;
  355. #else
  356.     case LIST_CMD:
  357.     case NLST_CMD:
  358.     case CWD_CMD:
  359.     case XPWD_CMD:
  360.     case PWD_CMD:
  361. #endif
  362.     case ACCT_CMD:        
  363.         usprintf(ftp.control,unimp);
  364.         break;
  365.     case DELE_CMD:
  366.         file = pathname(ftp.cd,arg);
  367.         if(!permcheck(&ftp,DELE_CMD,file)){
  368.              usprintf(ftp.control,noperm);
  369.         } else if(unlink(file) == 0){
  370.             usprintf(ftp.control,deleok);
  371.         } else {
  372.             usprintf(ftp.control,delefail,sys_errlist[errno]);
  373.         }
  374.         free(file);
  375.         break;
  376.     case PASS_CMD:
  377.         ftplogin(&ftp,arg);            
  378.         break;
  379. #ifndef    CPM
  380.     case XMKD_CMD:
  381.     case MKD_CMD:
  382.         file = pathname(ftp.cd,arg);
  383.         if(!permcheck(&ftp,MKD_CMD,file)){
  384.             usprintf(ftp.control,noperm);
  385. #ifdef    UNIX
  386.         } else if(mkdir(file,0777) == 0){
  387. #else
  388.         } else if(mkdir(file) == 0){
  389. #endif
  390.             usprintf(ftp.control,mkdok);
  391.         } else {
  392.             usprintf(ftp.control,cantmake,file,sys_errlist[errno]);
  393.         }
  394.         free(file);
  395.         break;
  396.     case XRMD_CMD:
  397.     case RMD_CMD:
  398.         file = pathname(ftp.cd,arg);
  399.         if(!permcheck(&ftp,RMD_CMD,file)){
  400.              usprintf(ftp.control,noperm);
  401.         } else if(rmdir(file) == 0){
  402.             usprintf(ftp.control,deleok);
  403.         } else {
  404.             usprintf(ftp.control,delefail,sys_errlist[errno]);
  405.         }
  406.         free(file);
  407.         break;
  408.     case STRU_CMD:
  409.         if(tolower(arg[0]) != 'f')
  410.             usprintf(ftp.control,unsupp);
  411.         else
  412.             usprintf(ftp.control,okay);
  413.         break;
  414.     case MODE_CMD:
  415.         if(tolower(arg[0]) != 's')
  416.             usprintf(ftp.control,unsupp);
  417.         else
  418.             usprintf(ftp.control,okay);
  419.         break;
  420.     }
  421. #endif
  422.     goto loop;
  423. finish:
  424.     log(ftp.control,"close FTP");
  425.     /* Clean up */
  426.     close_s(ftp.control);
  427.     if(ftp.data != -1)
  428.         close_s(ftp.data);
  429.     if(ftp.fp != NULLFILE)
  430.         fclose(ftp.fp);
  431.     free(ftp.username);
  432.     free(ftp.path);
  433.     free(ftp.cd);
  434. }
  435.  
  436. /* Shut down FTP server */
  437. int
  438. ftp0(argc,argv,p)
  439. int argc;
  440. char *argv[];
  441. void *p;
  442. {
  443.     close_s(Sftp);
  444.     Sftp = -1;
  445.     return 0;
  446. }
  447. static
  448. int
  449. pport(sock,arg)
  450. struct sockaddr_in *sock;
  451. char *arg;
  452. {
  453.     int32 n;
  454.     int i;
  455.  
  456.     n = 0;
  457.     for(i=0;i<4;i++){
  458.         n = atoi(arg) + (n << 8);
  459.         if((arg = strchr(arg,',')) == NULLCHAR)
  460.             return -1;
  461.         arg++;
  462.     }
  463.     sock->sin_addr.s_addr = n;
  464.     n = atoi(arg);
  465.     if((arg = strchr(arg,',')) == NULLCHAR)
  466.         return -1;
  467.     arg++;
  468.     n = atoi(arg) + (n << 8);
  469.     sock->sin_port = n;
  470.     return 0;
  471. }
  472. /* Attempt to log in the user whose name is in ftp->username and password
  473.  * in pass
  474.  */
  475. static void
  476. ftplogin(ftp,pass)
  477. struct ftpserv *ftp;
  478. char *pass;
  479. {
  480.     char buf[80],*cp,*cp1;
  481.     FILE *fp;
  482.     int anony = 0;
  483.  
  484.     if((fp = fopen(Userfile,READ_TEXT)) == NULLFILE){
  485.         /* Userfile doesn't exist */
  486.         usprintf(ftp->control,noperm);
  487.         return;
  488.     }
  489.     while(fgets(buf,sizeof(buf),fp),!feof(fp)){
  490.         if(buf[0] == '#')
  491.             continue;    /* Comment */
  492.         if((cp = strchr(buf,' ')) == NULLCHAR)
  493.             /* Bogus entry */
  494.             continue;
  495.         *cp++ = '\0';        /* Now points to password */
  496.         if(strcmp(ftp->username,buf) == 0)
  497.             break;        /* Found user name */
  498.     }
  499.     if(feof(fp)){
  500.         /* User name not found in file */
  501.         fclose(fp);
  502.         usprintf(ftp->control,noperm);
  503.         return;
  504.     }
  505.     fclose(fp);
  506.     /* Look for space after password field in file */
  507.     if((cp1 = strchr(cp,' ')) == NULLCHAR){
  508.         /* Invalid file entry */
  509.         usprintf(ftp->control,noperm);
  510.         return;
  511.     }
  512.     *cp1++ = '\0';    /* Now points to path field */
  513.     if(strcmp(cp,"*") == 0)
  514.         anony = 1;    /* User ID is password-free */
  515.     if(!anony && strcmp(cp,pass) != 0){
  516.         /* Password required, but wrong one given */
  517.         usprintf(ftp->control,noperm);
  518.         return;
  519.     }
  520.     if((cp = strchr(cp1,' ')) == NULLCHAR){
  521.         /* Permission field missing */
  522.         usprintf(ftp->control,noperm);
  523.         return;
  524.     }
  525.     *cp++ = '\0';    /* now points to permission field */
  526.  
  527.     /* Set up current directory and path prefix */
  528.     ftp->cd = strdup(cp1);
  529.     ftp->path = strdup(cp1);
  530.     
  531.     /* And finally set the permission bits */
  532.     ftp->perms = atoi(cp);
  533.  
  534.     usprintf(ftp->control,logged);
  535.     if(!anony)
  536.         log(ftp->control,"%s logged in",ftp->username);
  537.     else
  538.         log(ftp->control,"%s logged in, ID %s",ftp->username,pass);
  539. }        
  540.  
  541. #ifdef    MSDOS
  542. /* Illegal characters in a DOS filename */
  543. static char badchars[] = "\"[]:|<>+=;,";
  544. #endif
  545.  
  546. /* Return 1 if the file operation is allowed, 0 otherwise */
  547. static int
  548. permcheck(ftp,op,file)
  549. struct ftpserv *ftp;
  550. int op;
  551. char *file;
  552. {
  553.     char *cp;
  554.  
  555.     if(file == NULLCHAR || ftp->path == NULLCHAR)
  556.         return 0;    /* Probably hasn't logged in yet */
  557. #ifdef    MSDOS
  558.     /* Check for characters illegal in MS-DOS file names */
  559.     for(cp = badchars;*cp != '\0';cp++){
  560.         if(strchr(file,*cp) != NULLCHAR)
  561.             return 0;    
  562.     }
  563. #endif
  564. #if    (defined(AMIGA) || defined(MAC))
  565. #else
  566.     /* The target file must be under the user's allowed search path */
  567.     if(strncmp(file,ftp->path,strlen(ftp->path)) != 0)
  568.         return 0;
  569. #endif
  570.  
  571.     switch(op){
  572.     case RETR_CMD:
  573.         /* User must have permission to read files */
  574.         if(ftp->perms & FTP_READ)
  575.             return 1;
  576.         return 0;
  577.     case DELE_CMD:
  578.     case RMD_CMD:
  579.         /* User must have permission to (over)write files */
  580.         if(ftp->perms & FTP_WRITE)
  581.             return 1;
  582.         return 0;
  583.     case STOR_CMD:
  584.     case MKD_CMD:
  585.         /* User must have permission to (over)write files, or permission
  586.          * to create them if the file doesn't already exist
  587.          */
  588.         if(ftp->perms & FTP_WRITE)
  589.             return 1;
  590.         if(access(file,2) == -1 && (ftp->perms & FTP_CREATE))
  591.             return 1;
  592.         return 0;
  593.     }
  594.     return 0;    /* "can't happen" -- keep lint happy */
  595. }
  596. static int
  597. sendit(ftp,command,file)
  598. struct ftpserv *ftp;
  599. char *command;
  600. char *file;
  601. {
  602.     long total;
  603.     struct sockaddr_in dport;
  604.  
  605.     ftp->data = socket(AF_INET,SOCK_STREAM,0);
  606.     dport.sin_family = AF_INET;
  607.     dport.sin_addr.s_addr = Ip_addr;
  608.     dport.sin_port = IPPORT_FTPD;
  609.     bind(ftp->data,(char *)&dport,SOCKSIZE);
  610.     usprintf(ftp->control,sending,command,file);
  611.     if(connect(ftp->data,(char *)&ftp->port,SOCKSIZE) == -1){
  612.         fclose(ftp->fp);
  613.         ftp->fp = NULLFILE;
  614.         close_s(ftp->data);
  615.         ftp->data = -1;
  616.         usprintf(ftp->control,noconn);
  617.         return -1;
  618.     }
  619.     /* Do the actual transfer */
  620.     total = sendfile(ftp->fp,ftp->data,ftp->type);
  621.  
  622.     if(total == -1){
  623.         /* An error occurred on the data connection */
  624.         usprintf(ftp->control,noconn);
  625.         shutdown(ftp->data,2);    /* Blow away data connection */
  626.     } else {
  627.         usprintf(ftp->control,txok);
  628.     }
  629.     fclose(ftp->fp);
  630.     ftp->fp = NULLFILE;
  631.     close_s(ftp->data);
  632.     ftp->data = -1;
  633.     if(total == -1)
  634.         return -1;
  635.     else
  636.         return 0;
  637. }
  638. static int
  639. recvit(ftp,command,file)
  640. struct ftpserv *ftp;
  641. char *command;
  642. char *file;
  643. {
  644.     struct sockaddr_in dport;
  645.     long total;
  646.  
  647.     ftp->data = socket(AF_INET,SOCK_STREAM,0);
  648.     dport.sin_family = AF_INET;
  649.     dport.sin_addr.s_addr = Ip_addr;
  650.     dport.sin_port = IPPORT_FTPD;
  651.     bind(ftp->data,(char *)&dport,SOCKSIZE);
  652.     usprintf(ftp->control,sending,command,file);
  653.     if(connect(ftp->data,(char *)&ftp->port,SOCKSIZE) == -1){
  654.         fclose(ftp->fp);
  655.         ftp->fp = NULLFILE;
  656.         close_s(ftp->data);
  657.         ftp->data = -1;
  658.         usprintf(ftp->control,noconn);
  659.         return -1;
  660.     }
  661.     total = recvfile(ftp->fp,ftp->data,ftp->type);
  662.  
  663. #ifdef    CPM
  664.     if(ftp->type == ASCII_TYPE)
  665.         fputc(CTLZ,ftp->fp);
  666. #endif
  667.     if(total == -1) {
  668.         /* An error occurred while writing the file */
  669.         usprintf(ftp->control,writerr,sys_errlist[errno]);
  670.         shutdown(ftp->data,2);    /* Blow it away */
  671.     } else {
  672.         usprintf(ftp->control,rxok);
  673.         close_s(ftp->data);
  674.     }
  675.     ftp->data = -1;
  676.     fclose(ftp->fp);
  677.     ftp->fp = NULLFILE;
  678.     if(total == -1)
  679.         return -1;
  680.     else
  681.         return 0;
  682. }
  683.